package com.googlecode.sparda.commons.util;

import java.awt.Dimension;

/**
 * A {@link Sizer} can be used to simplify {@link Dimension} size logic. 
 * @author Fabio Grucci (<i>alias</i> <b>Phoenix</b>)
 *
 */
public class Sizer {
	/**
	 * The starting Dimension.
	 */
	private final Dimension baseDimension;
	/**
	 * The delta width.
	 */
	private final int deltaWidth;
	/**
	 * The delta height.
	 */
	private final int deltaHeight;
	/**
	 * Max {@link Dimension} allowed.
	 */
	private final Dimension maxDimension;
	/**
	 * Create a sizer whit linear increase capabilities.
	 * Like {@link #Sizer(Dimension, int, int)} whit width and height of baseDimension.
	 * @param baseDimension The base dimension
	 */
	public Sizer(Dimension baseDimension) {
		this(baseDimension, (int) baseDimension.getWidth(), (int) baseDimension.getHeight());
	}
	/**
	 * Create a sizer whit linear increase capabilities, and a max {@link Dimension}.
	 * Like {@link #Sizer(Dimension, Dimension, int, int)} whit width and height of baseDimension.
	 * @param baseDimension The base dimension
	 * @param maxDimension The max dimension
	 */
	public Sizer(Dimension baseDimension, Dimension maxDimension) {
		this(baseDimension, maxDimension, (int) baseDimension.getWidth(), (int) baseDimension.getHeight());
	}
	/**
	 * Create a sizer that increase the base dimension whit of a delta(Width/Height).
	 * Like {@link #Sizer(Dimension, Dimension, int, int)} whit unbounded max {@link Dimension} limit.
	 * @param baseDimension
	 * @param deltaWidth
	 * @param deltaHeight
	 */
	public Sizer(Dimension baseDimension, int deltaWidth, int deltaHeight) {
		this(baseDimension, Sizer.defaultMaxDimension(), deltaWidth, deltaHeight);
	}
	/**
	 * Create a sizer that increase the base dimension whit of a delta(Width/Height) bounded by a max {@link Dimension}.
	 * @param baseDimension The base dimension
	 * @param maxDimension The max dimension
	 * @param deltaWidth The delta of the width
	 * @param deltaHeight The delta of the width
	 */
	public Sizer(Dimension baseDimension, Dimension maxDimension, int deltaWidth, int deltaHeight) {
		this.baseDimension = baseDimension;
		this.maxDimension = maxDimension;
		this.deltaWidth = deltaWidth;
		this.deltaHeight = deltaHeight;
	}
	/**
	 * Method to get the actual dimension created starting from a raise factor.
	 * <ul>
	 * <li>If the raiseFactor is <code>0</code> resulting {@link Dimension} is {@link #baseDimension};</li>
	 * <li>If the raiseFactor is <code>1</code> resulting {@link Dimension} is {@link #baseDimension} <code> + 1 * delta(Width/Height)</code>;</li>
	 * <li>If the raiseFactor is <code>1.5</code> resulting {@link Dimension} is {@link #baseDimension} <code> + 1.5 * delta(Width/Height)</code>;</li>
	 * <li>And so on...</li>
	 * </ul>
	 * Everything bounded by {@link #maxDimension}.
	 * @param raiseFactor The raise Factor
	 * @return The resulting {@link Dimension}
	 */
	public Dimension getDimension(double raiseFactor) {
		/* Calculate new size */
		double newWidth = this.baseDimension.getWidth() + this.deltaWidth * raiseFactor;
		double newHeight = this.baseDimension.getHeight() + this.deltaHeight * raiseFactor;
		/* Now bound */
		newWidth = Math.min(newWidth, this.maxDimension.getWidth());
		newHeight = Math.min(newHeight, this.maxDimension.getHeight());
		/* Return the bounded dimension */
		return new Dimension((int) newWidth, (int) newHeight);
	}
	
	/* GETTER */
	/**
     * @return the baseDimension
     */
    public Dimension getBaseDimension() {
    	return baseDimension;
    }
	/**
     * @return the deltaWidth
     */
    public int getDeltaWidth() {
    	return deltaWidth;
    }
	/**
     * @return the deltaHeight
     */
    public int getDeltaHeight() {
    	return deltaHeight;
    }
	/**
     * @return the maxDimension
     */
    public Dimension getMaxDimension() {
    	return maxDimension;
    }
    
    /* STATIC */
	public static Sizer getLinearSizer(Dimension dimension) {
		return new Sizer(dimension);
	}
	
	public static Sizer getLinearSizer(Dimension dimension, Dimension maxDimesion) {
		return new Sizer(dimension, maxDimesion);
	}

	public static Sizer getScalarSizer(Dimension dimension, double scaleFactor) {
		return Sizer.getScalarSizer(dimension, Sizer.defaultMaxDimension(), scaleFactor);
	}
	
	public static Sizer getScalarSizer(Dimension dimension, Dimension maxDimension, double scaleFactor) {
		final double deltaWidth = dimension.getWidth() * scaleFactor;
		final double deltaHeigth = dimension.getHeight() * scaleFactor;
		return new Sizer(dimension, maxDimension, (int) deltaWidth, (int) deltaHeigth);
	}
	
	private static Dimension defaultMaxDimension() {
		return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
	}
	
}

